/* Copyright 2017, 2018, Gabriel Czernikier
 *
 * This file is part of Notehaus.
 * Notehaus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * Notehaus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with Notehaus.  If not, see <http://www.gnu.org/licenses/>.
 */
%{
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include "composer.h"
#include "lgwseq.h"
#include "parse_file.h"
#include "types.h"
int conflict_at_symbol = 0; // i.e. '@' symbol, gearing a usage from yylex like the following: if(next token was going to be '@' && conflict_at_symbol) { ungetc();/*or equivalently, draw ptr back before '@' */ conflict_at_symbol=false;/*clear flag*/ return BOGUS;}
lgwseq_t *lws;
struct search_context_st *sch_ctx; 
struct type_id_st *typ_id;
struct list_head cls_def_nesting_head;
%}
%union {
	struct class_def_st *class_def;
	wchar_t* descriptor;
	lgwseq_t *generic;
	struct token_list_st *token_list;
	struct list_head list_head;
	struct str_id_st *str_id;
	struct type_id_st *type_id;
	struct method_id_st *method_id;
	struct field_id_st *field_id;
	struct type_list_st *type_list;
	struct {
		struct {
			struct type_list_st *type_list;
			// struct identifier_list_st ...
		} formal_params;
	} method_decl_rest;
}
%start CompilationUnit
%token-table
%token BooleanLiteral
%token CharacterLiteral
%token FloatingPointLiteral
%token IntegerLiteral
%token NullLiteral
%token StringLiteral
%token <generic> Identifier
%token END 0 "end of file"
%token BOGUS
%token IMPLEMENTATION_ELISION
%type <class_def> NormalClassDeclaration;
%type <type_id> Type;
%type <method_decl_rest.formal_params> FormalParameters;
%type <method_decl_rest> MethodDeclaratorRest;
%type <method_decl_rest> MethodOrFieldRest;
%type <descriptor> BasicType;
%type <token_list> IdentifierMaybeQualified;
%{
LIST_HEAD(class_nesting_head);  // To keep track the nesting, as understood by this example "class A { class B { class C{} class D{}}}"
struct search_entry_st *search_parent, *search_pkg;
%}


%%
IdentifierMaybeQualified:
  Identifier  { $$=malloc(sizeof(struct token_list_st)); INIT_LIST_HEAD(&$$->token_list); $$->token=$1; }
  | IdentifierMaybeQualified '.' Identifier  { $$=malloc(sizeof(struct token_list_st)); INIT_LIST_HEAD(&$$->token_list); list_add(&$1->token_list, &$$->token_list); $$->token=$3;} 
  ;
  
IdentifierMaybeQualifiedList:
  IdentifierMaybeQualified
  | IdentifierMaybeQualifiedList ',' IdentifierMaybeQualified
  ;

CompilationUnit:
  /*empty*/
  | ImportDeclarationList
  | ImportDeclarationList TypeDeclarationList
  | TypeDeclarationList
  | Annotations "package" IdentifierMaybeQualified ';'
  | "package" IdentifierMaybeQualified ';'   { search_parent=search_pkg= add_package_search_entry($2); add_search_context_item(token_list(for_lgwseq(&lws, 1, L"*"), token_list(for_lgwseq(&lws, 4, L"lang"), token_list(for_lgwseq(&lws, 4, L"java"), NULL))) ,NULL); }
  | Annotations "package" IdentifierMaybeQualified ';' ImportDeclarationList
  | "package" IdentifierMaybeQualified ';' ImportDeclarationList
  | Annotations "package" IdentifierMaybeQualified ';' ImportDeclarationList TypeDeclarationList
  | "package" IdentifierMaybeQualified ';' ImportDeclarationList  TypeDeclarationList
  | Annotations "package" IdentifierMaybeQualified ';' TypeDeclarationList
  | "package" IdentifierMaybeQualified ';'  TypeDeclarationList
  ;

ImportDeclarationList:
  ImportDeclaration
  | ImportDeclarationList ImportDeclaration
  ;
  
TypeDeclarationList:
  TypeDeclaration
  | TypeDeclarationList TypeDeclaration
  ;
  
ImportDeclaration:
  "import" "static" IdentifierMaybeQualified '.' '*' ';'
  | "import" "static" IdentifierMaybeQualified ';'
  | "import" IdentifierMaybeQualified '.' '*' ';' { add_search_context_item(token_lst(for_lgwseq(1, L"*"), $2), NULL); }
  | "import"  IdentifierMaybeQualified ';'  { add_search_context_item($2, NULL); }
  ;

TypeDeclaration:
  ClassOrInterfaceDeclaration
  | ';'
  ;

ClassOrInterfaceDeclaration:
  InterfaceDeclaration
  | ClassDeclaration
  | ModifierList BOGUS InterfaceDeclaration
  | ModifierList  ClassDeclaration 
  ;

ClassDeclaration:
  NormalClassDeclaration
  | EnumDeclaration
  ;

InterfaceDeclaration:
  NormalInterfaceDeclaration
  | AnnotationTypeDeclaration
  ;

NormalClassDeclaration:
  "class" Identifier    ClassBody
  | "class" Identifier   "implements" TypeList ClassBody
  | "class" Identifier  "extends" Type  ClassBody
  | "class" Identifier "extends" IdentifierMaybeQualified "implements" TypeList { 
	if(search_pkg!=NULL) { 
		add_search_context_item(NULL, search_pkg); 
		search_pkg=NULL; 
	} 
	search_parent=add_reftype_search_entry(typ_id=add_type_id(add_str_id(fullqualif_from_schent(search_parent, $2))), $2, search_parent); 
	sch_ctx=push_search_context_copy(); 
	add_search_context_item(NULL, search_parent); 
	$$ = add_class_def(/* clstyp */ typ_id); 
	add_unresolved_type($4, sch_ctx, &$$->parenttyp);   // pin to class_def's parenttyp to be resolved later
	$$->parent_iface = $6;
	list_add(&$$->nesting_stack, &cls_def_nesting_head);
} ClassBody { list_del(&cls_def_nesting_head); }
  | "class" Identifier TypeParameters   ClassBody
  | "class" Identifier TypeParameters  "implements" TypeList ClassBody
  | "class" Identifier TypeParameters "extends" Type  ClassBody
  | "class" Identifier TypeParameters "extends" Type "implements" TypeList ClassBody
  ;

EnumDeclaration:
  "enum" Identifier  EnumBody
  | "enum" Identifier "implements" TypeList EnumBody
  ;

NormalInterfaceDeclaration:
  "interface" Identifier   InterfaceBody
  | "interface" Identifier  "extends" TypeList InterfaceBody
  | "interface" Identifier TypeParameters  InterfaceBody
  | "interface" Identifier TypeParameters "extends" TypeList InterfaceBody
  ;

AnnotationTypeDeclaration:
  '@' "interface" Identifier AnnotationTypeBody
  ;

Type:
  BasicType 
  | BasicType ArrayDesignatorList
  | ReferenceType 
  | ReferenceType ArrayDesignatorList
  ;

BasicType:
  "byte" { for_lgwseq(&lws, 1, L"B");}
  | "short" { for_lgwseq(&lws, 1, L"S");}
  | "char" { for_lgwseq(&lws, 1, L"C");}
  | "int" { for_lgwseq(&lws, 1, L"I");}
  | "long" { for_lgwseq(&lws, 1, L"J");}
  | "float" { for_lgwseq(&lws, 1, L"F");}
  | "double" { for_lgwseq(&lws, 1, L"D");}
  | "boolean" { for_lgwseq(&lws, 1, L"Z");}
  ;

ReferenceType:  /* TODO reduce action: add_type_id or malloc wchar_t plus add_search_entry. Let for the moment alone Arrays and Type arguments */
  Identifier  
  | Identifier TypeArguments 
  | ReferenceType '.' Identifier
  | ReferenceType '.' Identifier TypeArguments
  ;

TypeArguments:
  '<' TypeArgumentList '>'
  ;

TypeArgument:
  ReferenceType
  | '?' 
  | '?'   "super" ReferenceType 
  | '?'  "extends"  ReferenceType 
  ;

NonWildcardTypeArguments:
  '<' TypeList '>'
  ;

TypeList:
  ReferenceType 
  | TypeList ',' ReferenceType
  ;

TypeArgumentsOrDiamond:
  '<' '>'
  | TypeArguments
  ;

NonWildcardTypeArgumentsOrDiamond:
  '<' '>'
  | NonWildcardTypeArguments
  ;

TypeParameters:
  '<' TypeParameterList '>'
  ;

TypeParameter:
  Identifier 
  | Identifier "extends" Bound
  ;

Bound:
  ReferenceType 
  | Bound '&' ReferenceType
  ;

Modifier:
  Annotation
  | "public"
  | "protected"
  | "private"
  | "static"
  | "abstract"
  | "final"
  | "native"
  | "synchronized"
  | "transient"
  | "volatile"
  | "strictfp"
  ;

Annotations:
  Annotation 
  | Annotations Annotation
  ;

Annotation:
  '@' IdentifierMaybeQualified 
  | '@' IdentifierMaybeQualified  '('  ')' 
  | '@' IdentifierMaybeQualified  '(' AnnotationElement ')' 
  ;

AnnotationElement:
  ElementValuePairs
  | ElementValue
  ;

ElementValuePairs:
  ElementValuePair 
  | ElementValuePairs ',' ElementValuePair
  ;

ElementValuePair:
  Identifier '=' ElementValue
  ;

ElementValue:
  Annotation
  | Expression1
  | ElementValueArrayInitializer
  ;

ElementValueArrayInitializer:
  '{' ElementValuesList '}'
  ;

ClassBody:
  '{'  '}'
  | '{' ClassBodyDeclarationList '}'
  ;

ClassBodyDeclaration:
  ';'
  | MemberDecl
  | ModifierList  MemberDecl
  | Block
  | "static" Block
  ;

MemberDecl:
  MethodOrFieldDecl
  | "void" Identifier VoidMethodDeclaratorRest
  | Identifier ConstructorDeclaratorRest
  | GenericMethodOrConstructorDecl
  | ClassDeclaration
  | InterfaceDeclaration
  ;

MethodOrFieldDecl:
  Type Identifier MethodOrFieldRest { add_method_id(enclosing_class, add_proto_id($1, $3->formal_params->type_list),$2); }
  ;

MethodOrFieldRest:
  FieldDeclaratorsRest ';'
  | MethodDeclaratorRest
  ;

FieldDeclaratorsRest:
  VariableDeclaratorRest 
  | VariableDeclaratorRest VariableDeclaratorList
  ;

MethodDeclaratorRest:
  FormalParameters    ';' { $$.formal_params = $1; }
  | FormalParameters   Block
  | FormalParameters  "throws" IdentifierMaybeQualifiedList  ';'
  | FormalParameters  "throws" IdentifierMaybeQualifiedList Block 
  | FormalParameters ArrayDesignatorList   ';'
  | FormalParameters ArrayDesignatorList  Block 
  | FormalParameters ArrayDesignatorList "throws" IdentifierMaybeQualifiedList  ';'
  | FormalParameters ArrayDesignatorList "throws" IdentifierMaybeQualifiedList Block 
  ;

VoidMethodDeclaratorRest:
  FormalParameters   ';'
  | FormalParameters  Block 
  | FormalParameters "throws" IdentifierMaybeQualifiedList  ';'
  | FormalParameters "throws" IdentifierMaybeQualifiedList Block 
  ;

ConstructorDeclaratorRest:
  FormalParameters  Block
  | FormalParameters "throws" IdentifierMaybeQualifiedList Block
  | FormalParameters  IMPLEMENTATION_ELISION ';'
  | FormalParameters "throws" IdentifierMaybeQualifiedList IMPLEMENTATION_ELISION ';'
  ;

GenericMethodOrConstructorDecl:
  TypeParameters GenericMethodOrConstructorRest
  ;

GenericMethodOrConstructorRest:
   "void" Identifier VoidMethodDeclaratorRest
  | Type  Identifier MethodDeclaratorRest
  | Identifier ConstructorDeclaratorRest
  ;

InterfaceBody:
  '{'  '}'
  | '{' InterfaceBodyDeclarationList '}'
  ;

InterfaceBodyDeclaration:
  ';'
  | InterfaceMemberDecl
  | ModifierList  InterfaceMemberDecl
  ;

InterfaceMemberDecl:
  InterfaceMethodOrFieldDecl
  | "void" Identifier VoidInterfaceMethodDeclaratorRest
  | InterfaceGenericMethodDecl
  | ClassDeclaration
  | InterfaceDeclaration
  ;

InterfaceMethodOrFieldDecl:
  Type Identifier InterfaceMethodOrFieldRest
  ;

InterfaceMethodOrFieldRest:
  ConstantDeclaratorsRest ';' /* Like FieldDeclaratorsRest, but initializers have a compulsory "'=' value" */
  | InterfaceMethodDeclaratorRest
  ;

ConstantDeclaratorsRest:
  ConstantDeclaratorRest 
  | ConstantDeclaratorRest ConstantDeclaratorList
  ;

ConstantDeclaratorRest:
   '=' VariableInitializer
  | ArrayDesignatorList '=' VariableInitializer
  ;

ConstantDeclaratorList:
  ',' ConstantDeclarator
  | ConstantDeclaratorList ',' ConstantDeclarator
  ;

ConstantDeclarator:
  Identifier ConstantDeclaratorRest
  ;

InterfaceMethodDeclaratorRest:
  FormalParameters   ';'
  | FormalParameters  "throws" IdentifierMaybeQualifiedList ';'
  | FormalParameters ArrayDesignatorList  ';'
  | FormalParameters ArrayDesignatorList "throws" IdentifierMaybeQualifiedList ';'
  ;

VoidInterfaceMethodDeclaratorRest:
  FormalParameters  ';'
  | FormalParameters "throws" IdentifierMaybeQualifiedList ';'
  ;

InterfaceGenericMethodDecl:
  TypeParameters  "void" Identifier VoidInterfaceMethodDeclaratorRest
  | TypeParameters Type  Identifier InterfaceMethodDeclaratorRest
  ;

FormalParameters:
  '('  ')'
  | '(' FormalParameterDecls ')'  { $$.type_list= add_type_list();/*$$.identifier_list=the names of the parameter decls*/ }
  ;

FormalParameterDecls:
   Type FormalParameterDeclsRest { add_type_member($1);}
  | VariableModifierList Type FormalParameterDeclsRest { add_type_member($2);}
  ;

VariableModifier:
  "final"
  | Annotation
  ;

FormalParameterDeclsRest:
  VariableDeclaratorId 
  | VariableDeclaratorId ',' FormalParameterDecls
  | "..." VariableDeclaratorId
  ;

VariableDeclaratorId:
  Identifier 
  | Identifier ArrayDesignatorList
  ;

VariableDeclarators:
  VariableDeclarator
  | VariableDeclarator VariableDeclaratorList
  ;

VariableDeclarator:
  Identifier VariableDeclaratorRest
  ;

VariableDeclaratorRest:
  /*empty*/ 
  | '=' VariableInitializer 
  | ArrayDesignatorList 
  | ArrayDesignatorList  '=' VariableInitializer 
  ;

VariableInitializer:
  ArrayInitializer
  | Expression
  ;

ArrayInitializer:
  '{'  '}'
  | '{'  VariableInitializer    '}'
  | '{'  VariableInitializer  ','  '}'
  | '{'  VariableInitializer VariableInitializerList   '}'
  | '{'  VariableInitializer VariableInitializerList ','  '}'
  ;

Block:
  '{' BlockStatements '}'
  ;

BlockStatements:
  /*empty*/
  | BlockStatementList
  ;

BlockStatement:
  LocalVariableDeclarationStatement
  | ClassOrInterfaceDeclaration
  | Statement
  | Identifier ':' Statement
  ;

LocalVariableDeclarationStatement:
  Type VariableDeclarators ';'
  | VariableModifierList Type VariableDeclarators ';'
  ;

Statement:
  Block
  | ';'
  | Identifier ':' Statement
  | StatementExpression ';'
  | "if" ParExpression Statement 
  | "if" ParExpression Statement "else" Statement
  | "assert" Expression  ';'
  | "assert" Expression ':' Expression ';'
  | "switch" ParExpression '{' SwitchBlockStatementGroups '}'
  | "while" ParExpression Statement
  | "do" Statement "while" ParExpression ';'
  | "for" '(' ForControl ')' Statement
  | "break"  ';'
  | "break" Identifier ';'
  | "continue"  ';'
  | "continue" Identifier ';'
  | "return"  ';'
  | "return" Expression ';'
  | "throw" Expression ';'
  | "synchronized" ParExpression Block
  | "try" Block   Finally
  | "try" Block Catches 
  | "try" Block  Catches Finally
  | "try" ResourceSpecification Block  
  | "try" ResourceSpecification Block  Finally
  | "try" ResourceSpecification Block Catches 
  | "try" ResourceSpecification Block Catches Finally
  ;

StatementExpression:
  Expression
  ;

Catches:
  CatchClause 
  | Catches CatchClause
  ;

CatchClause:
  "catch" '('  CatchType Identifier ')' Block
  | "catch" '(' VariableModifierList CatchType Identifier ')' Block
  ;

CatchType:
  IdentifierMaybeQualified 
  | IdentifierMaybeQualified PipeSeparatedIdentifierMaybeQualifiedList
  ;

Finally:
  "finally" Block
  ;

ResourceSpecification:
  '(' Resources  ')'
  | '(' Resources ';' ')'
  ;

Resources:
  Resource 
  | Resources ';' Resource
  ;

Resource:
  ReferenceType VariableDeclaratorId '=' Expression
  | VariableModifierList ReferenceType VariableDeclaratorId '=' Expression
  ;

SwitchBlockStatementGroups:
  /*empty*/
  | SwitchBlockStatementGroupList
  ;

SwitchBlockStatementGroup:
  SwitchLabels BlockStatements
  ;

SwitchLabels:
  SwitchLabel 
  | SwitchLabels SwitchLabel
  ;

SwitchLabel:
  "case" Expression ':'
  | "case" EnumConstantName ':'
  | "default" ':'
  ;

EnumConstantName:
  Identifier
  ;

ForControl:
  ForVarControl
  | ForInit ';'  ';' 
  | ForInit ';'  ';' ForUpdate
  | ForInit ';' Expression ';' 
  | ForInit ';' Expression ';' ForUpdate
  ;

ForVarControl:
   Type VariableDeclaratorId ForVarControlRest
  | VariableModifierList Type VariableDeclaratorId ForVarControlRest
  ;

ForVarControlRest:
  ForVariableDeclaratorsRest ';'  ';' 
  | ForVariableDeclaratorsRest ';'  ';' ForUpdate
  | ForVariableDeclaratorsRest ';' Expression ';' 
  | ForVariableDeclaratorsRest ';' Expression ';' ForUpdate
  | ':' Expression
  ;

ForVariableDeclaratorsRest:
  /*empty*/ 
  | '=' VariableInitializer 
  | VariableDeclaratorList
  | '=' VariableInitializer VariableDeclaratorList
  ;

ForInit:
  ForUpdate
  ;

ForUpdate:
  StatementExpression 
  | ForUpdate ',' StatementExpression
  ;

Expression:
  Expression1 
  | Expression1 AssignmentOperator Expression1
  ;

AssignmentOperator:
  '='
  | "+="
  | "-="
  | "*="
  | "/="
  | "&="
  | "|="
  | "^="
  | "%="
  | "<<="
  | ">>="
  | ">>>="
  ;

Expression1:
  Expression2 
  | Expression2 Expression1Rest
  ;

Expression1Rest:
  '?' Expression ':' Expression1
  ;

Expression2:
  Expression3 
  | Expression3 Expression2Rest
  ;

Expression2Rest:
  //  empty alternative suppressed because both covered by and conflicting with Expression2: Expression3 
  InfixOpExpression3List
  | "instanceof" Type
  ;

InfixOp:
  "||"
  | "&&"
  | '|'
  | '^'
  | '&'
  | "=="
  | "!="
  | '<'
  | '>'
  | "<="
  | ">="
  | "<<"
  | ">>"
  | ">>>"
  | '+'
  | '-'
  | '*'
  | '/'
  | '%'
  ;

Expression3:
  PrefixOp Expression3
  | '('  Type ')'  Expression3
  | '(' Expression  ')'  Expression3
  | Primary  
  | Primary SelectorList 
  | Primary  PostfixOpList
  | Primary SelectorList PostfixOpList
  ;

PrefixOp:
  "++"
  | "--"
  | '!'
  | '~'
  | '+'
  | '-'
  ;

PostfixOp:
  "++"
  | "--"
  ;

Primary:
  Literal
  | ParExpression
  | "this" 
  | "this" Arguments
  | "super" SuperSuffix
  | "new" Creator
  | NonWildcardTypeArguments  "this" Arguments
  | NonWildcardTypeArguments ExplicitGenericInvocationSuffix 
  | Identifier  IdentifierSuffix
  | IdentifierMaybeQualified
  | IdentifierMaybeQualified IdentifierSuffix
  | BasicType  '.' "class"
  | BasicType ArrayDesignatorList '.' "class"
  | "void" '.' "class"
  ;

Literal:
  IntegerLiteral
  | FloatingPointLiteral
  | CharacterLiteral
  | StringLiteral
  | BooleanLiteral
  | NullLiteral
  ;

ParExpression:
  '(' Expression ')'
  ;

Arguments:
  '('  ')'
  | '('  Expression   ')'
  | '('  Expression ExpressionList  ')'
  ;

SuperSuffix:
  Arguments
  | '.' Identifier 
  | '.' Identifier Arguments
  ;

ExplicitGenericInvocationSuffix:
  "super" SuperSuffix
  | Identifier Arguments
  ;

Creator:
  NonWildcardTypeArguments CreatedName ClassCreatorRest
  | CreatedName  ArrayCreatorRest
  | CreatedName ClassCreatorRest 
  ;

CreatedName:
  Identifier  
  | Identifier TypeArgumentsOrDiamond 
  | Identifier  DiamondKindIdentifierList
  | Identifier TypeArgumentsOrDiamond DiamondKindIdentifierList
  ;

ClassCreatorRest:
  Arguments 
  | Arguments ClassBody
  ;

ArrayCreatorRest:
  '['  Expression ']'  
  | '[' ']'  ArrayInitializer 
  | '['  Expression ']'  ArrayDesignatorList
  | '[' ']' ArrayDesignatorList ArrayInitializer 
  | '['  Expression ']' SubscriptExpressionList 
  | '['  Expression ']' SubscriptExpressionList ArrayDesignatorList
  ;

IdentifierSuffix:
  '['  Expression ']'
  | '['  '.' "class"  ']'
  | '[' ArrayDesignatorList '.' "class"  ']'
  | Arguments
  | '.'  "new"  InnerCreator
  | '.'  "super" Arguments 
  | '.'  "this" 
  | '.'  ExplicitGenericInvocation 
  | '.' "class" 
  | '.'  "new" NonWildcardTypeArguments InnerCreator
  ;

ExplicitGenericInvocation:
  NonWildcardTypeArguments ExplicitGenericInvocationSuffix
  ;

InnerCreator:
  Identifier  ClassCreatorRest
  | Identifier NonWildcardTypeArgumentsOrDiamond ClassCreatorRest
  ;

Selector:
  '.' Identifier 
  | '.' Identifier Arguments
  | '.' ExplicitGenericInvocation
  | '.' "this"
  | '.' "super" SuperSuffix
  | '.' "new"  InnerCreator
  | '.' "new" NonWildcardTypeArguments InnerCreator
  | '[' Expression ']'
  ;

EnumBody:
  '{'    '}'
  | '{'   EnumBodyDeclarations '}'
  | '{'  ','  '}'
  | '{'  ',' EnumBodyDeclarations '}'
  | '{' EnumConstants   '}'
  | '{' EnumConstants  EnumBodyDeclarations '}'
  | '{' EnumConstants ','  '}'
  | '{' EnumConstants ',' EnumBodyDeclarations '}'
  ;

EnumConstants:
  EnumConstant
  | EnumConstants ',' EnumConstant
  ;

EnumConstant:
  Identifier
  | Identifier  ClassBody
  | Identifier Arguments 
  | Identifier Arguments ClassBody
  | Annotations Identifier
  | Annotations Identifier  ClassBody
  | Annotations Identifier Arguments 
  | Annotations Identifier Arguments ClassBody
  ;

EnumBodyDeclarations:
  ';' 
  | ';' ClassBodyDeclarationList
  ;

AnnotationTypeBody:
  '{'  '}'
  | '{' AnnotationTypeElementDeclarations '}'
  ;

AnnotationTypeElementDeclarations:
  AnnotationTypeElementDeclaration
  | AnnotationTypeElementDeclarations AnnotationTypeElementDeclaration
  ;

AnnotationTypeElementDeclaration:
   AnnotationTypeElementRest
  | ModifierList BOGUS AnnotationTypeElementRest
  ;

AnnotationTypeElementRest:
  Type Identifier AnnotationMethodOrConstantRest ';'
  | ClassDeclaration
  | InterfaceDeclaration
/*| EnumDeclaration  // suppressed because both comprehended in and conflicting with ClassDeclaration */
/*| AnnotationTypeDeclaration  // suppressed because both comprehended in and conflicting with InterfaceDeclaration */
  ;

AnnotationMethodOrConstantRest:
  AnnotationMethodRest
  | ConstantDeclaratorsRest
  ;

AnnotationMethodRest:
  '(' ')'  
  | '(' ')'  "default" ElementValue
  | '(' ')' '[' ']' 
  | '(' ')' '[' ']' "default" ElementValue

PostfixOpList:
  PostfixOp
  | PostfixOpList PostfixOp
  ;

ClassBodyDeclarationList:
  ClassBodyDeclaration
  | ClassBodyDeclarationList ClassBodyDeclaration
  ;

PipeSeparatedIdentifierMaybeQualifiedList:
  '|' IdentifierMaybeQualified
  | PipeSeparatedIdentifierMaybeQualifiedList '|' IdentifierMaybeQualified
  ;

VariableModifierList:
  VariableModifier
  | VariableModifierList VariableModifier
  ;

VariableDeclaratorList:
  ',' VariableDeclarator
  | VariableDeclaratorList ',' VariableDeclarator
  ;

SubscriptExpressionList:
  '[' Expression ']'
  | SubscriptExpressionList '[' Expression ']'
  ;

TypeArgumentList:
  TypeArgument
  | TypeArgumentList ',' TypeArgument
  ;

InterfaceBodyDeclarationList:
  InterfaceBodyDeclaration
  | InterfaceBodyDeclarationList InterfaceBodyDeclaration
  ;

ExpressionList:
  ',' Expression
  | ExpressionList ',' Expression
  ;

SelectorList:
  Selector
  | SelectorList Selector
  ;

TypeParameterList:
  TypeParameter
  | TypeParameterList ',' TypeParameter
  ;

ModifierList:
  Modifier  {conflict_at_symbol = 1; }
  | ModifierList BOGUS Modifier
  ;

VariableInitializerList:
  ',' VariableInitializer
  | VariableInitializerList ',' VariableInitializer
  ;

ElementValuesList:
  ','
  | ElementValue
  | ElementValuesList  ','
  | ElementValuesList ElementValue
  ;

SwitchBlockStatementGroupList:
  SwitchBlockStatementGroup
  | SwitchBlockStatementGroupList SwitchBlockStatementGroup
  ;

BlockStatementList:
  BlockStatement
  | BlockStatementList BlockStatement
  ;

ArrayDesignatorList:
  '[' ']'
  | ArrayDesignatorList '[' ']'
  ;

InfixOpExpression3List:
  InfixOp Expression3
  | InfixOpExpression3List InfixOp Expression3
  ;

DiamondKindIdentifierList:
  '.' Identifier 
  | '.' Identifier TypeArgumentsOrDiamond
  | DiamondKindIdentifierList '.' Identifier 
  | DiamondKindIdentifierList '.' Identifier TypeArgumentsOrDiamond
  ;
%%
#include "wtname.h"
int
wtname_lookup(const wchar_t *ptr, size_t len) {
  // Adapted from a code borrowed from Bison's manual
  int i;
  for (i = 0; i != YYNTOKENS; i++)
  {
    if (wtname[i] != 0
    && ! wcsncmp (&wtname[i][1], ptr,
    len)
    && wtname[i][len + 2] == L'\0')
      break;
  }
  return i==YYNTOKENS?-1:mytoknum[i];
}

void
yyerror (char const *s)
{
  fprintf (stderr, "%s\n", s);
}
